package org.usmile.algorithms.huawei.acm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Scanner;

public class _快速开租建站 {


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int taskNum = sc.nextInt();
        int relationsNum = sc.nextInt();

        int[][] relations = new int[relationsNum][2];
        for (int i = 0; i < relationsNum; i++) {
            relations[i][0] = sc.nextInt();
            relations[i][1] = sc.nextInt();
        }

        System.out.println(getResult(relations, taskNum));
    }

    public static int getResult(int[][] relations, int taskNum) {
        HashMap<Integer, ArrayList<Integer>> nextTaskMap = new HashMap<>();
        int[] inDegree = new int[taskNum];
        for (int[] relation : relations) {
            int prevTask = relation[0];
            int nextTask = relation[1];

            nextTaskMap.putIfAbsent(prevTask, new ArrayList<>());
            nextTaskMap.get(prevTask).add(nextTask); // a的下一个顶点有b
            inDegree[nextTask]++; // b顶点的入度++
        }

        LinkedList<Integer[]> queue = new LinkedList<>();

        int finishTime = 1;
        for (int taskId = 0; taskId < taskNum; taskId++) {
            if (inDegree[taskId] == 0) {
                queue.add(new Integer[]{taskId, finishTime}); // i含义是入度为0的顶点，t含义是该顶点所处建站时间
            }
        }

        while (queue.size() > 0) {
            Integer[] prevTask = queue.removeFirst(); // 注意这里为了维持t，一定要使用队列先进先出，出队代表删除某顶点
            int prevTaskId = prevTask[0];
            int prevTaskTime = prevTask[1];
            if (nextTaskMap.containsKey(prevTaskId) && nextTaskMap.get(prevTaskId).size() > 0) {
                for (Integer nextTaskId : nextTaskMap.get(prevTaskId)) {
                    // 该顶点被删除，则其后继点的入度值--，若--后入度为0，则将成为新的出队点
                    if (--inDegree[nextTaskId] == 0) {
                        finishTime = prevTaskTime + 1; // 此时建站时间+1
                        queue.add(new Integer[]{nextTaskId, finishTime});
                    }
                }
            }
        }

        return finishTime;
    }
}
